package com.fy.service.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.fy.common.constant.CmdConstants;
import com.fy.common.constant.RedisKeyConstant;
import com.fy.common.dto.GroupCreateDto;
import com.fy.common.dto.GroupInfoDto;
import com.fy.common.entity.*;
import com.fy.common.enums.SkImChatSessionEnum;
import com.fy.common.enums.SkImCommonStatusEnum;
import com.fy.common.enums.SkImGroupEnum;
import com.fy.common.enums.SkImUserRequestEnum;
import com.fy.common.model.im.MessageModel;
import com.fy.common.util.ImUtil;
import com.fy.common.util.TokenUtil;
import com.fy.dao.mapper.SkImGroupMapper;
import com.fy.framework.common.model.R;
import com.fy.framework.component.config.LocaleMessage;
import com.fy.framework.component.config.RedissonComponet;
import com.fy.framework.component.config.TenantContextHolder;
import com.fy.service.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.redisson.api.RMapCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @author zhshuo
 * @date 2021/12/17 18:19
 */
@Slf4j
@Service
public class SkImGroupServiceImpl extends ServiceImpl<SkImGroupMapper, SkImGroup> implements SkImGroupService {

    LocaleMessage localeMessage;
    MessageService messageService;
    ImBrokerService imBrokerService;
    RedissonComponet redissonComponet;
    RocketMQTemplate rocketMQTemplate;
    SkImUserInfoService userInfoService;
    ImBrokerGroupService brokerGroupService;
    SkImChatSessionService chatSessionService;
    SkImUserRequestService userRequestService;
    SkImGroupMemberService groupMemberService;

    @Value("${spring.rocketmq.consumer.brokerMessageTopic}")
    String brokerMessageTopic;

    @Override
    @Transactional(rollbackFor=Exception.class)
    public void create(GroupCreateDto groupCreateDto) {
        List<Long> nameIds = new ArrayList<>();
        Set<Long> userIds = new HashSet<>();
        userIds.add(TokenUtil.getUserId());
        nameIds.add(TokenUtil.getUserId());
        if (CollectionUtils.isNotEmpty(groupCreateDto.getInviteMembers())) {
            userIds.addAll(groupCreateDto.getInviteMembers());
            nameIds.add(groupCreateDto.getInviteMembers().get(0));
        }

        List<SkImUserInfo> skImUserInfos = userInfoService.selectList(new EntityWrapper<SkImUserInfo>().in("sk_im_user_id",userIds));
        Map<Long, SkImUserInfo> imUserInfoMap = skImUserInfos.stream().collect(Collectors.toMap(SkImUserInfo::getSkImUserId, Function.identity()));
        String name = skImUserInfos.stream().filter(e -> nameIds.contains(e.getSkImUserId())).map(SkImUserInfo::getUsername).collect(Collectors.joining());
        SkImGroup imGroup = new SkImGroup().setName(name).setType(groupCreateDto.getGroupType().getValue())
                .setMemberCount(userIds.size());
        insert(imGroup);
        List<SkImGroupMember> skImGroupMembers = new ArrayList<>(userIds.size());
        List<SkImChatSession> skImChatSessions = new ArrayList<>();

        userIds.forEach(userId -> {
            SkImGroupMember skImGroupMember = new SkImGroupMember().setSkImGroupId(imGroup.getId())
                    .setSkImUserId(userId).setUserRole(userId.equals(TokenUtil.getUserId())?SkImGroupEnum.GROUP_OWNER.getValue(): SkImGroupEnum.GROUP_MEMBER.getValue())
                    .setUserNickName(imUserInfoMap.get(userId).getUsername()).setGroupNickName(groupCreateDto.getName());
            skImGroupMembers.add(skImGroupMember);
            //TODO
            SkImChatSession skImChatSession = new SkImChatSession().setType(SkImChatSessionEnum.GROUP.getType())
                    .setSkImUserId(userId).setSessionId(ImUtil.chatSessionIdGenGroup(userId, imGroup.getId()))
                    .setTargetId(imGroup.getId());
            skImChatSessions.add(skImChatSession);
            redissonComponet.setMap(RedisKeyConstant.USER_CHAT_SESSION+userId,ImUtil.chatSessionIdGenGroup(userId,imGroup.getId()),skImChatSession);
            redissonComponet.setMap(RedisKeyConstant.GROUP_MEMBERS+imGroup.getId(),String.valueOf(userId) ,new JSONObject());
            RMapCache<String, Object> map = redissonComponet.getMap(RedisKeyConstant.NIM_USER_INFO);
            if(map.containsKey(userId.toString())){
                JSONObject jsonObject = (JSONObject) map.get(userId.toString());
                Object userGroup = jsonObject.get("userGroup");
                JSONArray jsonArray = new JSONArray();
                if(Objects.nonNull(userGroup)){
                    jsonArray = (JSONArray) userGroup;
                }
                jsonArray.add(imGroup.getId());
                jsonObject.put("userGroup",jsonArray);
                map.put(userId.toString(),jsonObject);
            }
        });
        MessageModel messageModel = new MessageModel();
        messageModel.setContent(skImUserInfos.stream().map(SkImUserInfo::getUsername).collect(Collectors.joining("、")));
        messageModel.setToGroup(imGroup.getId());
        messageModel.setCmd(CmdConstants.RESPONSE_ADD_GROUP);
        messageModel.setTenantId(TenantContextHolder.getTenant());
        messageService.saveGroupMessage(messageModel);
        //Message
        rocketMQTemplate.convertAndSend(brokerMessageTopic, JSON.toJSONString(messageModel));
        groupMemberService.insertBatch(skImGroupMembers);
        chatSessionService.insertBatch(skImChatSessions);
    }

    @Override
    public void infoEdit(GroupInfoDto groupInfoDto) {
        baseMapper.updateInfo(groupInfoDto);
    }

    @Override
    public void disband(Long groupId) {
        update(new SkImGroup().setStatus(SkImGroupEnum.STATUS_DISBAND.getValue()),new EntityWrapper<SkImGroup>().eq("id",groupId));
        redissonComponet.delete(RedisKeyConstant.GROUP_MEMBERS+groupId);
    }

    @Override
    public R<?> inviteIntoGroup(Long groupId, Long userId) {
        SkImGroupMember groupMember = groupMemberService.selectOne(new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId)
                .eq("sk_im_user_id", TokenUtil.getUserId()).eq("status", SkImCommonStatusEnum.NORAML.getStatus()));
        if(Objects.isNull(groupMember)){
            return R.failedAlter(localeMessage.getMessage("im.group.userStatusError"));
        }

        SkImGroup imGroup = selectById(groupId);
        SkImUserInfo imUserInfo = userInfoService.selectOne(new EntityWrapper<SkImUserInfo>().eq("sk_im_user_id", userId));

        Integer userRole = groupMember.getUserRole();
        if(userRole.equals(SkImGroupEnum.GROUP_OWNER.getValue()) || (userRole.equals(SkImGroupEnum.GROUP_MANAGER.getValue()) && imGroup.getManagerJoinVerify().equals(Boolean.TRUE))){
            //群主 或者 管理员拥有审核权限
            SkImGroupMember skImGroupMember = new SkImGroupMember().setSkImGroupId(groupId)
                    .setSkImUserId(userId).setUserRole(SkImGroupEnum.GROUP_OWNER.getValue())
                    .setUserNickName(imUserInfo.getUsername()).setGroupNickName(imGroup.getName()).setJoinWay(SkImGroupEnum.JOIN_INVITE.getValue()).setInviteUser(TokenUtil.getUserId());
            groupMemberService.insert(skImGroupMember);
            SkImChatSession skImChatSession = new SkImChatSession().setType(SkImChatSessionEnum.GROUP.getType())
                    .setSkImUserId(userId).setSessionId(ImUtil.chatSessionIdGenGroup(userId, imGroup.getId()))
                    .setTargetId(imGroup.getId());
            chatSessionService.insert(skImChatSession);
            MessageModel messageModel = new MessageModel();
            messageModel.setCmd(CmdConstants.RESPONSE_INVITE_GROUP_SUCCESS);
            messageModel.setFrom(userId);
            messageModel.setTenantId(TenantContextHolder.getTenant());
            messageModel.setToGroup(imGroup.getId());
            brokerGroupService.sendGroupMessage(messageModel,false);
            //todo
            redissonComponet.setMap(RedisKeyConstant.USER_CHAT_SESSION+userId,ImUtil.chatSessionIdGenGroup(userId,imGroup.getId()),skImChatSession);
            redissonComponet.setMap(RedisKeyConstant.GROUP_MEMBERS+imGroup.getId(),String.valueOf(userId) ,new JSONObject());
            RMapCache<String, Object> map = redissonComponet.getMap(RedisKeyConstant.NIM_USER_INFO);
            if(map.containsKey(userId.toString())){
                JSONObject jsonObject = (JSONObject) map.get(userId.toString());
                Object userGroup = jsonObject.get("userGroup");
                JSONArray jsonArray = new JSONArray();
                if(Objects.nonNull(userGroup)){
                    jsonArray = (JSONArray) userGroup;
                }
                jsonArray.add(imGroup.getId());
                jsonObject.put("userGroup",jsonArray);
                map.put(userId.toString(),jsonObject);
            }
            update(new SkImGroup().setMemberCount(imGroup.getMemberCount()+1),new EntityWrapper<SkImGroup>().eq("id",imGroup.getId()));
        }else{
            List<Long> ids = new ArrayList<>();
            SkImGroupMember groupOwner = groupMemberService.selectOne(new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId)
                    .eq("user_role", SkImGroupEnum.GROUP_OWNER.getValue()).eq("status", SkImCommonStatusEnum.NORAML.getStatus()));
            ids.add(groupOwner.getSkImUserId());
            if(imGroup.getManagerJoinVerify().equals(Boolean.TRUE)){
                //管理员有审核进群的权限
                List<SkImGroupMember> groupMembers = groupMemberService.selectList(new EntityWrapper<SkImGroupMember>().eq("sk_im_group_id", groupId)
                        .eq("user_role", SkImGroupEnum.GROUP_MANAGER.getValue()).eq("status", SkImCommonStatusEnum.NORAML.getStatus()));
                if(CollectionUtils.isNotEmpty(groupMembers)){
                    ids.addAll(groupMembers.stream().map(SkImGroupMember::getSkImUserId).collect(Collectors.toList()));
                }
            }
            //普通群员
            userRequestService.insert(new SkImUserRequest().setSkImUserId(userId).setTargetId(groupId).setRequestType(SkImUserRequestEnum.GROUP.getValue())
                    .setInviteUser(TokenUtil.getUserId()).setStatus(SkImUserRequestEnum.PROCESSING.getValue()));
            MessageModel messageModel = new MessageModel();
            messageModel.setCmd(CmdConstants.RESPONSE_INVITE_GROUP_VERIFY);
            messageModel.setTenantId(TenantContextHolder.getTenant());
            messageModel.setFrom(userId);
            messageModel.setContent(imUserInfo.getUsername());
            imBrokerService.commonAddressingMessage(messageModel,ids,false);
        }
        return R.success(localeMessage.getMessage("im.common.successful"));
    }

    @Autowired
    public void setLocaleMessage(LocaleMessage localeMessage) {
        this.localeMessage = localeMessage;
    }

    @Autowired
    public void setMessageService(MessageService messageService) {
        this.messageService = messageService;
    }

    @Autowired
    public void setImBrokerService(ImBrokerService imBrokerService) {
        this.imBrokerService = imBrokerService;
    }

    @Autowired
    public void setRedissonComponet(RedissonComponet redissonComponet) {
        this.redissonComponet = redissonComponet;
    }

    @Autowired
    public void setRocketMQTemplate(RocketMQTemplate rocketMQTemplate) {
        this.rocketMQTemplate = rocketMQTemplate;
    }

    @Autowired
    public void setUserInfoService(SkImUserInfoService userInfoService) {
        this.userInfoService = userInfoService;
    }

    @Autowired
    public void setBrokerGroupService(ImBrokerGroupService brokerGroupService) {
        this.brokerGroupService = brokerGroupService;
    }

    @Autowired
    public void setChatSessionService(SkImChatSessionService chatSessionService) {
        this.chatSessionService = chatSessionService;
    }

    @Autowired
    public void setUserRequestService(SkImUserRequestService userRequestService) {
        this.userRequestService = userRequestService;
    }

    @Autowired
    public void setGroupMemberService(SkImGroupMemberService groupMemberService) {
        this.groupMemberService = groupMemberService;
    }

}
